/*
 * ImageContainer.cpp
 *
 *  Created on: 28/07/2011
 *      Author: solnox
 */

#include "ImageContainer.h"
#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <map>

#if defined(WIN32) || defined(_WIN32)
# define FILE_SEP "\\"
#else
# define FILE_SEP "/"
#endif


using namespace std;

ImageContainer::ImageContainer() {
	image_ctr_ = 0;
}

ImageContainer::~ImageContainer() {
	for(unsigned int i = 0; i < input_images_.size(); i++)
	{
		cv::Mat * img_ptr = input_images_.back();
		input_images_.pop_back();
		delete img_ptr;
	}
}

std::string ImageContainer::getNextImageName()
{
	if(image_ctr_ >= input_image_names_.size()) // there are no more images left
	{
		return string();
	}
	return input_image_names_.at(image_ctr_);

}

cv::Mat * ImageContainer::getNextImage()
{
	if(image_ctr_ >= input_images_.size()) // there are no more images left
	{
		return NULL;
	}

	return input_images_.at(image_ctr_++);

}

cv::Mat * ImageContainer::getLastImage()
{
	if(input_images_.size() == 0) // there are no more images left
	{
		return NULL;
	}

	return input_images_.at(input_images_.size()-1);

}


std::vector<cv::Mat*>  ImageContainer::getAllImages()
{
	return input_images_;
}


bool ImageContainer::loadImages(std::string path_name, std::string file_ending)
{
	//cout << path_name << endl;
	list<string> image_names;
	if(getFiles(path_name, image_names, file_ending) != 0)
		return false;


	list<string>::iterator it;
	for (it=image_names.begin(); it!=image_names.end(); ++it)
	{
		//cout << *it << endl;
		cv::Mat image = cv::imread(*it);
		if(image.data != NULL)
		{
			cv::Mat * img_ptr = new cv::Mat(image);
			if(img_ptr != NULL)
			{
				input_image_names_.push_back(*it);
				input_images_.push_back(img_ptr);
			}
			else
			{
				cerr << "loadImages : img_ptr == NULL" << endl;
			}
		}
		else
		{
			cerr << "loadImages : image.data == NULL" << endl;
		}

	}
	return true;
}

int ImageContainer::getFiles(string dir, list<string> &files, std::string file_ending)
{
	DIR *dp;
	struct dirent *dirp;
	if((dp  = opendir(dir.c_str())) == NULL) {
		cout << "Error(" << errno << ") opening " << dir << endl;
		return errno;
	}

	while ((dirp = readdir(dp)) != NULL) {
		string file_name(dirp->d_name);

		if(endingEquals(file_name,file_ending))
			files.push_back(dir + FILE_SEP + file_name);
	}
	closedir(dp);
	sortNames(files);
	return 0;
}

void ImageContainer::sortNames(list<string> &names)
{
	vector< list<string> > list_vec;
	map<unsigned int, unsigned int> lengths2ind;
	map<unsigned int, unsigned int>::iterator map_it;
	list<unsigned int> possible_lengths;

	unsigned int ind_counter = 0;

	for (list<string>::iterator it=names.begin(); it!=names.end(); ++it)
	{
		string current_name = *it;
		unsigned int length = current_name.size();

		int index = 0;
		map_it = lengths2ind.find(length);
		if(map_it == lengths2ind.end()) // there does not yet exit an entry of this length
		{
			possible_lengths.push_back(length);
			index = ind_counter++;
			lengths2ind.insert(pair<unsigned int, unsigned int>(length,index));


			list<string> new_list;
			list_vec.push_back(new_list);
		}
		else
		{
			index = map_it->second;
		}

		list_vec.at(index).push_back(current_name);
		//cout << list_vec.at(index).size() << endl;

	}
	// remove all entries from old map
	names.clear();

	// reenter in right order
	possible_lengths.sort();
	for (list<unsigned int>::iterator length_it=possible_lengths.begin(); length_it!=possible_lengths.end(); ++length_it)
	{
		int current_length = *length_it;
		map_it = lengths2ind.find(current_length);
		assert(map_it != lengths2ind.end());
		list<string> current_list = list_vec.at(map_it->second);
		current_list.sort();
		for (list<string>::iterator it=current_list.begin(); it!=current_list.end(); ++it)
		{
			names.push_back(*it);
		}
	}

}

bool ImageContainer::endingEquals(string query_name, string ending)
{

	//cout << "name_length: "<<  query_name.size() << " ending length: "<< ending.size() << endl;
	//cout << query_name << endl;
	if(ending.size() > query_name.length())
		return false;
	string query_ending = query_name.substr(query_name.size() - ending.size(), ending.size());
	//cout << query_ending << endl;
	int num_not_matches = ending.compare(query_ending);
	if(num_not_matches == 0)
		return true;
	else
		return false;
}



